package io.cici.cc.mybatis.lite.reflection;

import java.lang.reflect.*;


public class TypeParameterResolver {

    private TypeParameterResolver() {
    }


    public static Type resolveFieldType(Field field, Type srcType) {
        Type fieldType = field.getGenericType();
        Class<?> declaringClass = field.getDeclaringClass();
        return resolveType(srcType, declaringClass, fieldType);
    }


    public static Type resolveReturnType(Type mapperInterface, Method method) {

        Class<?> declaringClass = method.getDeclaringClass();
        Type returnType = method.getGenericReturnType();
        return resolveType(mapperInterface, declaringClass, returnType);
    }


    public static Type[] resolveParamTypes(Method method, Type srcType) {
        Type[] paramTypes = method.getGenericParameterTypes();
        Class<?> declaringClass = method.getDeclaringClass();
        Type[] result = new Type[paramTypes.length];
        for (int i = 0; i < paramTypes.length; i++) {
            result[i] = resolveType(srcType, declaringClass, paramTypes[i]);
        }
        return result;
    }

    private static Type resolveType(Type srcType, Class<?> declaringClass, Type type) {
        if (type instanceof TypeVariable) {
            throw new IllegalArgumentException();
        } else if (type instanceof ParameterizedType) {
            return resolveParameterizedType((ParameterizedType) type, srcType, declaringClass);
        } else if (type instanceof GenericArrayType) {
            throw new IllegalArgumentException();
        } else {
            return type;
        }
    }

    private static ParameterizedType resolveParameterizedType(ParameterizedType parameterizedType, Type srcType,
                                                              Class<?> declaringClass) {
        Class<?> rawType = (Class<?>) parameterizedType.getRawType();
        Type[] typeArgs = parameterizedType.getActualTypeArguments();
        Type[] args = new Type[typeArgs.length];
        for (int i = 0; i < typeArgs.length; i++) {
            if (typeArgs[i] instanceof TypeVariable) {
                throw new IllegalArgumentException();
            } else if (typeArgs[i] instanceof ParameterizedType) {
                throw new IllegalArgumentException();
            } else if (typeArgs[i] instanceof WildcardType) {
                throw new IllegalArgumentException();
            } else {
                args[i] = typeArgs[i];
            }
        }
        return new ParameterizedTypeImpl(rawType, null, args);
    }


}
